////////////////////////////////////////////////////////////////////////////
//
//  Crytek Engine Source File.
//  Copyright (C), Crytek Studios, 2001-2007.
// -------------------------------------------------------------------------
//  File name:   CryFixedString.h
//  Version:     v1.00
//  Created:     14/03/2007 by AlexL.
//  Compilers:   Visual Studio.NET 2005
//  Description: Stack-based fixed-size String class, similar to CryString.
//               will switch to heap-based allocation when string does no longer fit
//               Can easily be substituted instead of CryString.
// -------------------------------------------------------------------------
//  History:
//
////////////////////////////////////////////////////////////////////////////

#ifndef __CRYFIXEDSTRING_H__
#define __CRYFIXEDSTRING_H__
#pragma once

#include <string.h>
#include <wchar.h>
#include <limits.h>
#include <stdarg.h>
#include <ctype.h>
#include <wctype.h>

#ifndef CRY_STRING_DEBUG
#define CRY_STRING_DEBUG(s)
#endif

template <class T> struct CharTraits;

// traits for char
template <>
class CharTraits<char> 
{
public:
	typedef size_t size_type;
	typedef char value_type;
	typedef const value_type* const_str;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef pointer iterator;
	typedef const_pointer const_iterator;

	ILINE int _isspace(value_type c) const
	{
		return ::isspace( (int)c );
	}

	ILINE value_type _traits_toupper(value_type c) const
	{
		return toupper(c);
	}

	ILINE value_type _traits_tolower(value_type c) const
	{
		return tolower(c);
	}

	ILINE value_type _ascii_tolower(value_type c) const
	{
		return ( (((c) >= 'A') && ((c) <= 'Z')) ? ((c) - 'A' + 'a') : (c) );
	}

	ILINE int _strcmp ( const_str a, const_str b) const
	{
		return ::strcmp(a, b);
	}

	ILINE int _strncmp ( const_str a, const_str b, size_type n) const
	{
		return ::strncmp(a, b, n);
	}

	ILINE int _stricmp ( const_str a, const_str b) const
	{
		return ::stricmp(a, b);
	}

	ILINE int _strnicmp ( const_str a, const_str b, size_type n) const
	{
		return strnicmp(a, b, n);
	}

	ILINE size_type _strspn( const_str str, const_str strCharSet ) const
	{
		return (str == NULL) ? 0 : (size_type)::strspn(str, strCharSet);
	}

	ILINE size_type _strcspn( const_str str, const_str strCharSet ) const
	{
		return (str == NULL) ? 0 : (size_type)::strcspn(str, strCharSet);
	}

	static ILINE size_type _strlen( const_str str )
	{
		return (str == NULL) ? 0 : (size_type)::strlen(str);
	}

	ILINE const_str _strchr( const_str str, value_type c) const
	{
		return (str == NULL) ? 0 : ::strchr(str, c);
	}

	ILINE value_type* _strstr( value_type* str, const_str strSearch) const
	{
    return (str == NULL) ? 0 : (value_type*) ::strstr(str, strSearch);
	}

	ILINE void _copy( value_type *dest,const value_type *src,size_type count )
	{
		memcpy( dest,src,count*sizeof(value_type) );
	}

	ILINE void _move( value_type *dest,const value_type *src,size_type count )
	{
		memmove( dest,src,count*sizeof(value_type) );
	}

	ILINE void _set( value_type *dest,value_type ch,size_type count )
	{
		memset( dest,ch,count*sizeof(value_type) );
	}

	ILINE int	_vsnprintf( value_type *str, size_type size, const_str format, va_list ap)
	{
		return ::vsnprintf_s(str, size+1, size, format, ap);
	}
};

// traits for wchar_t
template <>
class CharTraits<wchar_t>
{
public:
	typedef size_t size_type;
	typedef wchar_t value_type;
	typedef const value_type* const_str;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef pointer iterator;
	typedef const_pointer const_iterator;

	ILINE int _isspace(value_type c) const
	{
		return iswspace(c);
	}

	ILINE value_type _traits_toupper(value_type c) const
	{
		return towupper(c);
	}

	ILINE value_type _traits_tolower(value_type c) const
	{
		return towlower(c);
	}

	ILINE value_type _ascii_tolower(value_type c) const
	{
		return towlower(c);
	}

	ILINE int _strcmp ( const_str a, const_str b) const
	{
		return wcscmp (a, b);
	}

	ILINE int _strncmp ( const_str a, const_str b, size_type n) const
	{
		return wcsncmp (a, b, n);
	}

	ILINE int _stricmp ( const_str a, const_str b) const
	{
		return wcsicmp(a, b);
	}

	ILINE int _strnicmp ( const_str a, const_str b, size_type n) const
	{
		return wcsnicmp(a, b, n);
	}

	ILINE size_type _strspn( const_str str, const_str strCharSet ) const
	{
		return (str == NULL) ? 0 : (size_type)::wcsspn(str, strCharSet);
	}

	ILINE size_type _strcspn( const_str str, const_str strCharSet ) const
	{
		return (str == NULL) ? 0 : (size_type)::wcscspn(str, strCharSet);
	}

	static ILINE size_type _strlen( const_str str )
	{
		return (str == NULL) ? 0 : (size_type)::wcslen(str);
	}

	ILINE const_str _strchr( const_str str, value_type c) const
	{
		return (str == NULL) ? 0 : ::wcschr(str, c);
	}

	ILINE value_type* _strstr( value_type* str, const_str strSearch) const
	{
		return (str == NULL) ? 0 : ::wcsstr(str, strSearch);
	}

	ILINE void _copy( value_type *dest,const value_type *src,size_type count )
	{
		memcpy( dest,src,count*sizeof(value_type) );
	}

	ILINE void _move( value_type *dest,const value_type *src,size_type count )
	{
		memmove( dest,src,count*sizeof(value_type) );
	}

	ILINE void _set( value_type *dest,value_type ch,size_type count )
	{
		wmemset( dest,ch,count );
	}

	ILINE int	_vsnprintf( value_type *str, size_type size, const_str format, va_list ap)
	{
		return ::_vsnwprintf_s(str, size+1, size, format, ap);
	}

};

template <class T, size_t S>
class CryStackStringT : public CharTraits<T>
{
public:
	//////////////////////////////////////////////////////////////////////////
	// Types compatible with STL string.
	//////////////////////////////////////////////////////////////////////////
	typedef CryStackStringT<T,S> _Self;
	typedef size_t size_type;
	typedef T value_type;
	typedef const value_type* const_str;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef pointer iterator;
	typedef const_pointer const_iterator;
	static const size_type MAX_SIZE = S;

	enum _npos_type {
		npos = (size_type)~0
	};

	//////////////////////////////////////////////////////////////////////////
	// Constructors
	//////////////////////////////////////////////////////////////////////////
	CryStackStringT();

public:

	CryStackStringT( const _Self& str );
	CryStackStringT( const _Self& str,size_type nOff,size_type nCount );
	explicit CryStackStringT( value_type ch, size_type nRepeat = 1 );
	CryStackStringT( const_str str );
#if defined(PS3) || defined(LINUX) || defined(CAFE)
	CryStackStringT( const CryStringT<T> &str );
#endif
	CryStackStringT( const_str str, size_type nLength );
	CryStackStringT( const_iterator _First,const_iterator _Last );
	~CryStackStringT();

	//////////////////////////////////////////////////////////////////////////
	// STL string like interface.
	//////////////////////////////////////////////////////////////////////////
	//! Operators.
	size_type length() const;
	size_type size() const;
	bool empty() const;
	void clear();  // free up the data

	//! Returns the storage currently allocated to hold the string, a value at least as large as length().
	//  Also: capacity is always >= (MAX_SIZE-1)
	size_type capacity() const;

	// Sets the capacity of the string to a number at least as great as a specified number.
	// nCount = 0 is shrinking string to fit number of characters in it.
	// Shrink to fit post-cond: capacity() >= (MAX_SIZE-1)
	void reserve( size_type nCount=0 );

	_Self& append( const value_type* _Ptr );
	_Self& append( const value_type* _Ptr,size_type nCount );
	_Self& append( const _Self& _Str,size_type nOff,size_type nCount );
	_Self& append( const _Self& _Str );
	_Self& append( size_type nCount,value_type _Ch );
	_Self& append( const_iterator _First,const_iterator _Last );

	_Self& assign( const_str _Ptr );
	_Self& assign( const_str _Ptr, size_type nCount );
	_Self& assign( const _Self& _Str, size_type off, size_type nCount );
	_Self& assign( const _Self& _Str );
	_Self& assign( size_type nCount, value_type _Ch );
	_Self& assign( const_iterator _First,const_iterator _Last );

	value_type  at( size_type index ) const;
	//value_type& at( size_type index );

	const_iterator begin() const { return m_str; };
	const_iterator end() const { return m_str+length(); };

	iterator begin() { return m_str; };
	iterator end() { return m_str+length(); };

	//! cast to C string operator.
	operator const_str() const { return m_str; }

	//! cast to C string.
	const value_type *c_str() const { return m_str; }
	const value_type *data() const { return m_str; };

	//////////////////////////////////////////////////////////////////////////
	// string comparasion.
	//////////////////////////////////////////////////////////////////////////
	int compare( const _Self& _Str ) const;
	int compare( size_type _Pos1,size_type _Num1,const _Self& _Str ) const;
	int compare( size_type _Pos1,size_type _Num1,const _Self& _Str,size_type nOff,size_type nCount ) const;
	int compare( const value_type* _Ptr	) const;
	int compare( size_type _Pos1,size_type _Num1,const value_type* _Ptr	) const;
	int compare( size_type _Pos1,size_type _Num1,const value_type* _Ptr,size_type _Num2 = npos	) const;

	// Case insensitive comparison
	int compareNoCase( const _Self& _Str ) const;
	int compareNoCase( size_type _Pos1,size_type _Num1,const _Self& _Str ) const;
	int compareNoCase( size_type _Pos1,size_type _Num1,const _Self& _Str,size_type nOff,size_type nCount ) const;
	int compareNoCase( const value_type* _Ptr	) const;
	int compareNoCase( size_type _Pos1,size_type _Num1,const value_type* _Ptr	) const;
	int compareNoCase( size_type _Pos1,size_type _Num1,const value_type* _Ptr,size_type _Num2 = npos	) const;

	// Copies at most a specified number of characters from an indexed position in a source string to a target character array.
	size_type copy( value_type* _Ptr, size_type nCount,	size_type nOff = 0 ) const;

	void push_back( value_type _Ch ) { _ConcatenateInPlace( &_Ch, 1 ); }
	void resize( size_type nCount,value_type _Ch=' ');

	//! simple sub-string extraction
	_Self substr( size_type pos, size_type count=npos ) const;

	// replace part of string.
	_Self& replace( value_type chOld, value_type chNew );
	_Self& replace( const_str strOld, const_str strNew );
	_Self& replace( size_type pos,size_type count,const_str strNew );
	_Self& replace( size_type pos,size_type count,const_str strNew,size_type count2 );
	_Self& replace( size_type pos,size_type count,size_type nNumChars,value_type chNew);

	// insert new elements to string.
	_Self& insert(size_type nIndex,value_type ch);
	_Self& insert(size_type nIndex,size_type nCount, value_type ch);
	_Self& insert(size_type nIndex,const_str pstr);
	_Self& insert(size_type nIndex,const_str pstr,size_type nCount );

	//! delete count characters starting at zero-based index
	_Self& erase( size_type nIndex,size_type count=npos );

	//! searching (return starting index, or -1 if not found)
	//! look for a single character match
	//! like "C" strchr
	size_type find( value_type ch,size_type pos = 0 ) const;
	//! look for a specific sub-string
	//! like "C" strstr
	size_type find( const_str subs,size_type pos = 0 ) const;
	size_type rfind( value_type ch,size_type pos = npos ) const; 

	size_type find_first_of( value_type _Ch,size_type nOff = 0 ) const;
	size_type find_first_of( const_str charSet,size_type nOff = 0 ) const;
	//size_type find_first_of( const value_type* _Ptr,size_type _Off,size_type _Count ) const;
	size_type find_first_of( const _Self& _Str, size_type _Off = 0 ) const;

	size_type find_first_not_of( value_type _Ch,size_type _Off=0 ) const;
	size_type find_first_not_of( const value_type* _Ptr,size_type _Off=0 ) const;
	size_type find_first_not_of( const value_type* _Ptr,size_type _Off,size_type _Count ) const;
	size_type find_first_not_of( const _Self& _Str,size_type _Off = 0 ) const;

	void swap( _Self& _Str );

	//////////////////////////////////////////////////////////////////////////
	// overloaded operators.
	//////////////////////////////////////////////////////////////////////////
	// overloaded indexing.
	value_type operator[]( size_type index ) const;
	//	value_type&	operator[]( size_type index ); // same as at()

	// overloaded assignment
	_Self& operator=( const _Self& str );
	_Self& operator=( value_type ch );
	_Self& operator=( const_str str );
#if defined(PS3) || defined(LINUX) || defined(CAFE)
	_Self& operator=( const CryStringT<T> &str );
#endif

	void move(_Self& src);

#if defined(LINUX)
	template<size_t AnySize>
	_Self& operator=(const CryStackStringT<T, AnySize> &str)
	{
		_Assign( str.c_str(),str.size() ) ;
		return *this;
	}
#endif 	
	
	// string concatenation
	_Self& operator+=( const _Self& str );
	_Self& operator+=( value_type ch );
	_Self& operator+=( const_str str );
#if defined(PS3) || defined(LINUX) || defined(CAFE)
	_Self& operator+=( const CryStringT<T> &str );
#endif	
	//template <class TT> friend CryStackStringT<TT> operator+( const CryStackStringT<TT>& str1, const CryStackStringT<TT>& str2 );
	//template <class TT> friend CryStackStringT<TT> operator+( const CryStackStringT<TT>& str, value_type ch );
	//template <class TT> friend CryStackStringT<TT> operator+( value_type ch, const CryStackStringT<TT>& str );
	//template <class TT> friend CryStackStringT<TT> operator+( const CryStackStringT<TT>& str1, const_str str2 );
	//template <class TT> friend CryStackStringT<TT> operator+( const_str str1, const CryStackStringT<TT>& str2 );

	// Workaround: X360 compiler crash (XDK: 5426)
#ifndef XENON
	size_t GetAllocatedMemory() const
	{
		size_t size = sizeof(*this);
		if (m_str != m_strBuf)
			size += (m_nAllocSize+1)*sizeof(value_type);
		return size;
	}
#endif

	//////////////////////////////////////////////////////////////////////////
	// Extended functions.
	// This functions are not in the STL string.
	// They have an ATL CString interface.
	//////////////////////////////////////////////////////////////////////////
	//! Format string, use (sprintf)
	_Self& Format( const value_type* format,... );

	//! Format string fast, directly formats into string's buffer.
	//  Make sure there is enough space to hold the string
	_Self& FormatFast ( const value_type* format,... );

	// This is _fast_ version
	_Self& MakeLower();
	// This is correct version
	_Self& MakeLowerLocale();
	_Self& MakeUpper();

	_Self& Trim();
	_Self& Trim( value_type ch );
	_Self& Trim( const value_type *sCharSet );

	_Self& TrimLeft();
	_Self& TrimLeft( value_type ch );
	_Self& TrimLeft( const value_type *sCharSet );

	_Self& TrimRight();
	_Self& TrimRight( value_type ch );
	_Self& TrimRight( const value_type *sCharSet );

	_Self SpanIncluding( const_str charSet ) const;
	_Self SpanExcluding( const_str charSet ) const;
	_Self Tokenize( const_str charSet, int &nStart ) const;
	_Self Mid( size_type nFirst,size_type nCount=npos ) const {  return substr(nFirst,nCount); };

	_Self Left( size_type count ) const;
	_Self Right( size_type count ) const;
	//////////////////////////////////////////////////////////////////////////

	// public utilities.
	static bool _IsValidString( const_str str );

public:
	//////////////////////////////////////////////////////////////////////////
	// Only used for debugging statistics.
	//////////////////////////////////////////////////////////////////////////
	static size_t _usedMemory( size_t size )
	{
		static size_t s_used_memory = 0;
		s_used_memory += size;
		return s_used_memory;
	}

	//private:
public:
	size_type   m_nLength;
	size_type   m_nAllocSize;
	value_type* m_str;								// pointer to ref counted string data
	value_type  m_strBuf[MAX_SIZE];

	// implementation helpers
	void _AllocData( size_type nLen );
	void _FreeData(value_type* pData);
	void _Free();
	void _Initialize();

	void _Concatenate( const_str sStr1,size_type nLen1,const_str sStr2,size_type nLen2 );
	void _ConcatenateInPlace( const_str sStr,size_type nLen );
	void _Assign( const_str sStr,size_type nLen );
	void _MakeUnique();
};


/////////////////////////////////////////////////////////////////////////////
// CryStackStringT<T,S> Implementation
//////////////////////////////////////////////////////////////////////////

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline bool CryStackStringT<T,S>::_IsValidString( const_str  )
{
	return true;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::_Assign( const_str sStr,size_type nLen )
{
	// Check if this string is shared (reference count greater then 1) or not enough capacity to store new string.
	// Then allocate new string buffer.
	if (nLen > capacity())
	{
		_Free();
		_AllocData(nLen);
	}
	// Copy characters from new string to this buffer.
	CharTraits<T>::_copy( m_str,sStr,nLen );
	// Set new length.
	m_nLength = nLen;
	// Make null terminated string.
	m_str[nLen] = 0;
	CRY_STRING_DEBUG(m_str)
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::_Concatenate( const_str sStr1,size_type nLen1,const_str sStr2,size_type nLen2 )
{
	size_type nLen = nLen1 + nLen2;
	if (nLen1 * 2 > nLen)
		nLen = nLen1 * 2;
	if (nLen != 0)
	{
		if (nLen < 8)
			nLen = 8;
		_AllocData(nLen);
		CharTraits<T>::_copy( m_str,sStr1,nLen1 );
		CharTraits<T>::_copy( m_str+nLen1, sStr2,nLen2 );
		m_nLength = nLen1 + nLen2;
		m_str[nLen1 + nLen2] = 0;
	}
	CRY_STRING_DEBUG(m_str)
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::_ConcatenateInPlace( const_str sStr,size_type nLen )
{
	if (nLen != 0)
	{
		// Check if this string is shared (reference count greater then 1) or not enough capacity to store new string.
		// Then allocate new string buffer.
		if (length()+nLen > capacity())
		{
			value_type* pOldData = m_str;
			_Concatenate( m_str,length(),sStr,nLen );
			_FreeData(pOldData);
		}
		else
		{
			CharTraits<T>::_copy( m_str+length(), sStr, nLen );
			m_nLength += nLen;
			m_str[m_nLength] = 0; // Make null terminated string.
		}
	}
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::_MakeUnique()
{
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::_Initialize()
{
	m_strBuf[0] = 0;
	m_str = m_strBuf;
	m_nLength = 0;
	m_nAllocSize = MAX_SIZE-1; // 0 termination not counted!
}

// always allocate one extra character for '\0' termination
// assumes [optimistically] that data length will equal allocation length
template <class T, size_t S>
inline void CryStackStringT<T,S>::_AllocData( size_type nLen )
{
	assert(nLen >= 0);
	assert(nLen <= INT_MAX-1);    // max size (enough room for 1 extra)

	if (nLen == 0)
		_Initialize();
	else
	{
		size_type allocLen = (nLen+1)*sizeof(value_type);
		value_type* pData = m_strBuf;
		if (allocLen > MAX_SIZE)
		{
			pData = (value_type*)CryModuleMalloc(allocLen);
			_usedMemory( allocLen ); // For statistics.
			m_nAllocSize = nLen;
		}
		else
		{
			m_nAllocSize = MAX_SIZE-1;
		}
		m_nLength = nLen;
		m_str = pData;
		m_str[nLen] = 0; // null terminated string.
	}
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::_Free()
{
	_FreeData(m_str);
	_Initialize();
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::_FreeData(value_type* pData)
{
	if (pData != m_strBuf)
	{
		size_t allocLen = (m_nAllocSize+1)*sizeof(value_type);
		_usedMemory( -check_cast<ptrdiff_t>(allocLen) ); // For statistics.
		CryModuleFree(pData);
	}
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>::CryStackStringT()
{
	_Initialize();
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>::CryStackStringT( const CryStackStringT<T,S>& str )
{
	_Initialize();
	_Assign(str.c_str(), str.length());
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>::CryStackStringT( const CryStackStringT<T,S>& str,size_type nOff,size_type nCount )
{
	_Initialize();
	assign( str,nOff,nCount );
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>::CryStackStringT( const_str str )
{
	_Initialize();
	// Make a copy of C string.
	size_type nLen = this->_strlen(str);
	if (nLen != 0)
	{
		_AllocData(nLen);
		CharTraits<T>::_copy( m_str,str,nLen );
		CRY_STRING_DEBUG(m_str)
	}
}

//////////////////////////////////////////////////////////////////////////
#if defined(PS3) || defined(LINUX) || defined(CAFE)
template <class T, size_t S>
inline CryStackStringT<T,S>::CryStackStringT( const CryStringT<T> &str )
{
	_Initialize();
	size_t nLength = str.size();
	if (nLength > 0)
	{
		_AllocData(nLength);
		CharTraits<T>::_copy( m_str,str.c_str(),nLength );
		CRY_STRING_DEBUG(m_str)
	}
}
#endif
//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>::CryStackStringT( const_str str,size_type nLength )
{
	_Initialize();
	if (nLength > 0)
	{
		_AllocData(nLength);
		CharTraits<T>::_copy( m_str,str,nLength );
		CRY_STRING_DEBUG(m_str)
	}
}


//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>::CryStackStringT( value_type ch,size_type nRepeat )
{
	_Initialize();
	if (nRepeat > 0)
	{
		_AllocData( nRepeat );
		CharTraits<T>::_set( m_str,ch,nRepeat );
		CRY_STRING_DEBUG(m_str)
	}
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>::CryStackStringT( const_iterator _First,const_iterator _Last )
{
	_Initialize();
	size_type nLength = (size_type)(_Last-_First);
	if (nLength > 0)
	{
		_AllocData(nLength);
		CharTraits<T>::_copy( m_str,_First,nLength );
		CRY_STRING_DEBUG(m_str)
	}
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>::~CryStackStringT()
{
	_FreeData(m_str);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::length() const
{
	return m_nLength;
}
template <class T, size_t S>
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::size() const
{
	return m_nLength;
}
template <class T, size_t S>
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::capacity() const
{
	return m_nAllocSize;
}

template <class T, size_t S>
inline bool CryStackStringT<T,S>::empty() const
{
	return length() == 0;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::clear()
{
	if (length() == 0)
		return;
	_Free();
	assert( length() == 0);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::reserve( size_type nCount )
{
	// Reserve of 0 is shrinking container to fit number of characters in it..
	if (nCount > capacity())
	{
		value_type* pOldData = m_str;
		size_type nOldLength = m_nLength;
		_AllocData( nCount );
		CharTraits<T>::_copy( m_str,pOldData,nOldLength);
		m_nLength = nOldLength;
		m_str[m_nLength] = 0;
		_FreeData(pOldData);
	} else if (nCount == 0)
	{
		if (length() != capacity())
		{
			value_type* pOldData = m_str;
			if (pOldData != m_strBuf)  // in case we fit into our static buffer, we cannot shrink anyway
			{
				size_type nOldLength = m_nLength;
				_AllocData(m_nLength);
				// if (pOldData != m_strBuf || m_str != m_strBuf) // actually always true
				// {
				CharTraits<T>::_copy( m_str,pOldData,nOldLength ); // we can safely use CharTraits<T>::_copy, as we never overlap here (in case of static buffer, we don't shrink anyway)
				_FreeData(pOldData);
				// }
			}
		}
	}
	CRY_STRING_DEBUG(m_str)
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::append( const_str _Ptr )
{
	*this += _Ptr;
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::append( const_str _Ptr, size_type nCount )
{
	_ConcatenateInPlace( _Ptr,nCount );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::append( const CryStackStringT<T,S>& _Str, size_type off, size_type nCount )
{
	size_type len = _Str.length();
	if (off > len)
		return *this;
	if (off+nCount > len)
		nCount = len - off;
	_ConcatenateInPlace( _Str.m_str+off,nCount );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::append( const CryStackStringT<T,S>& _Str )
{
	*this += _Str;
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::append( size_type nCount, value_type _Ch )
{
	if (nCount > 0)
	{
		if (length()+nCount >= capacity())
		{
			value_type* pOldData = m_str;
			size_type nOldLength = m_nLength;
			_AllocData( length()+nCount );
			CharTraits<T>::_copy( m_str, pOldData, nOldLength );
			CharTraits<T>::_set( m_str+nOldLength,_Ch,nCount );
			_FreeData(pOldData);
		}
		else
		{
			size_type nOldLength = length();
			CharTraits<T>::_set( m_str+nOldLength,_Ch,nCount );
			m_nLength = nOldLength + nCount;
			m_str[length()] = 0; // Make null terminated string.
		}
	}
	CRY_STRING_DEBUG(m_str)
		return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::append(  const_iterator _First,const_iterator _Last )
{
	append( _First,(size_type)(_Last-_First) );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::assign( const_str _Ptr )
{
	*this = _Ptr;
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::assign( const_str _Ptr, size_type nCount )
{
	size_type len = this->_strlen(_Ptr);
	_Assign( _Ptr,(nCount<len)?nCount:len );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::assign( const CryStackStringT<T,S>& _Str, size_type off, size_type nCount )
{
	size_type len = _Str.length();
	if (off > len)
		return *this;
	if (off+nCount > len)
		nCount = len - off;
	_Assign( _Str.m_str+off,nCount );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::assign( const CryStackStringT<T,S>& _Str )
{
	*this = _Str;
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::assign( size_type nCount, value_type _Ch )
{
	if (nCount >= 1)
	{
		_AllocData( nCount );
		CharTraits<T>::_set( m_str,_Ch,nCount );
		CRY_STRING_DEBUG(m_str)
	}
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S>& CryStackStringT<T,S>::assign( const_iterator _First,const_iterator _Last )
{
	assign( _First,(size_type)(_Last-_First) );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline typename CryStackStringT<T,S>::value_type CryStackStringT<T,S>::at( size_type index ) const
{
	assert( index >= 0 && index < length() );
	return m_str[index];
}

/*
inline value_type& CryStackStringT<T,S>::at( size_type index )
{
// same as GetAt
assert( index >= 0 && index < length() );
return m_str[index];
}
*/

template <class T, size_t S>
inline typename CryStackStringT<T,S>::value_type CryStackStringT<T,S>::operator[]( size_type index ) const
{
	assert( index >= 0 && index < length() );
	return m_str[index];
}


/*
inline value_type& CryStackStringT<T,S>::operator[]( size_type index )
{
// same as GetAt
assert( index >= 0 && index < length() );
return m_str[index];
}
*/


//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline int CryStackStringT<T,S>::compare( const CryStackStringT<T,S>& _Str ) const
{
	return CharTraits<T>::_strcmp( m_str,_Str.m_str );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compare( size_type _Pos1,size_type _Num1,const CryStackStringT<T,S>& _Str ) const
{
	return compare( _Pos1,_Num1,_Str.m_str,npos );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compare( size_type _Pos1,size_type _Num1,const CryStackStringT<T,S>& _Str,size_type nOff,size_type nCount ) const
{
	assert( nOff < _Str.length() );
	return compare( _Pos1,_Num1,_Str.m_str+nOff,nCount );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compare( const value_type* _Ptr	) const
{
	return CharTraits<T>::_strcmp( m_str,_Ptr );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compare( size_type _Pos1,size_type _Num1,const value_type* _Ptr	) const
{
	return compare( _Pos1,_Num1,_Ptr,npos );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compare( size_type _Pos1,size_type _Num1,const value_type* _Ptr,size_type _Num2 ) const
{
	assert( _Pos1 < length() );
	if (length() - _Pos1 < _Num1)
		_Num1 = length() - _Pos1; // trim to size

	int res = _Num1 == 0 ? 0 : CharTraits<T>::_strncmp( m_str+_Pos1,_Ptr,(_Num1 < _Num2)?_Num1:_Num2);
	return (res != 0 ? res : _Num1 < _Num2 ? -1 : _Num1 == _Num2 ? 0 : +1);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline int CryStackStringT<T,S>::compareNoCase( const CryStackStringT<T,S>& _Str ) const
{
	return CharTraits<T>::_stricmp( m_str,_Str.m_str );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compareNoCase( size_type _Pos1,size_type _Num1,const CryStackStringT<T,S>& _Str ) const
{
	return compareNoCase( _Pos1,_Num1,_Str.m_str,npos );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compareNoCase( size_type _Pos1,size_type _Num1,const CryStackStringT<T,S>& _Str,size_type nOff,size_type nCount ) const
{
	assert( nOff < _Str.length() );
	return compareNoCase( _Pos1,_Num1,_Str.m_str+nOff,nCount );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compareNoCase( const value_type* _Ptr	) const
{
	return CharTraits<T>::_stricmp( m_str,_Ptr );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compareNoCase( size_type _Pos1,size_type _Num1,const value_type* _Ptr	) const
{
	return compareNoCase( _Pos1,_Num1,_Ptr,npos );
}

template <class T, size_t S>
inline int CryStackStringT<T,S>::compareNoCase( size_type _Pos1,size_type _Num1,const value_type* _Ptr,size_type _Num2 ) const
{
	assert( _Pos1 < length() );
	if (length() - _Pos1 < _Num1)
		_Num1 = length() - _Pos1; // trim to size

	int res = _Num1 == 0 ? 0 : CharTraits<T>::_strnicmp( m_str+_Pos1,_Ptr,(_Num1 < _Num2)?_Num1:_Num2);
	return (res != 0 ? res : _Num1 < _Num2 ? -1 : _Num1 == _Num2 ? 0 : +1);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::copy( value_type* _Ptr, size_type nCount,size_type nOff ) const
{
	assert(nOff < length());
	if (nCount < 0)
		nCount = 0;
	if (nOff+nCount > length()) // trim to offset.
		nCount = length() - nOff;

	CharTraits<T>::_copy( _Ptr,m_str+nOff,nCount );
	return nCount;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline void CryStackStringT<T,S>::resize( size_type nCount,value_type _Ch )
{
	_MakeUnique();
	if (nCount > length())
	{
		size_type numToAdd = nCount - length();
		append(numToAdd,_Ch);
	}
	else if (nCount < length())
	{
		m_nLength = nCount;
		m_str[length()] = 0; // Make null terminated string.
	}
}

//////////////////////////////////////////////////////////////////////////
//! compare helpers
template <class T, size_t S> inline bool operator==(const CryStackStringT<T,S>& s1, const CryStackStringT<T,S>& s2)
{ return s1.compare(s2) == 0; }
template <class T, size_t S> inline bool operator==(const CryStackStringT<T,S>& s1, const typename CryStackStringT<T,S>::value_type* s2)
{ return s1.compare(s2) == 0; }
template <class T, size_t S> inline bool operator==(const typename CryStackStringT<T,S>::value_type* s1, const CryStackStringT<T,S>& s2)
{ return s2.compare(s1) == 0; }
template <class T, size_t S> inline bool operator!=(const CryStackStringT<T,S>& s1, const CryStackStringT<T,S>& s2)
{ return s1.compare(s2) != 0; }
template <class T, size_t S> inline bool operator!=(const CryStackStringT<T,S>& s1, const typename CryStackStringT<T,S>::value_type* s2)
{ return s1.compare(s2) != 0; }
template <class T, size_t S> inline bool operator!=(const typename CryStackStringT<T,S>::value_type* s1, const CryStackStringT<T,S>& s2)
{ return s2.compare(s1) != 0; }
template <class T, size_t S> inline bool operator<(const CryStackStringT<T,S>& s1, const CryStackStringT<T,S>& s2)
{ return s1.compare(s2) < 0; }
template <class T, size_t S> inline bool operator<(const CryStackStringT<T,S>& s1, const typename CryStackStringT<T,S>::value_type* s2)
{ return s1.compare(s2) < 0; }
template <class T, size_t S> inline bool operator<(const typename CryStackStringT<T,S>::value_type* s1, const CryStackStringT<T,S>& s2)
{ return s2.compare(s1) > 0; }
template <class T, size_t S> inline bool operator>(const CryStackStringT<T,S>& s1, const CryStackStringT<T,S>& s2)
{ return s1.compare(s2) > 0; }
template <class T, size_t S> inline bool operator>(const CryStackStringT<T,S>& s1, const typename CryStackStringT<T,S>::value_type* s2)
{ return s1.compare(s2) > 0; }
template <class T, size_t S> inline bool operator>(const typename CryStackStringT<T,S>::value_type* s1, const CryStackStringT<T,S>& s2)
{ return s2.compare(s1) < 0; }
template <class T, size_t S> inline bool operator<=(const CryStackStringT<T,S>& s1, const CryStackStringT<T,S>& s2)
{ return s1.compare(s2) <= 0; }
template <class T, size_t S> inline bool operator<=(const CryStackStringT<T,S>& s1, const typename CryStackStringT<T,S>::value_type* s2)
{ return s1.compare(s2) <= 0; }
template <class T, size_t S> inline bool operator<=(const typename CryStackStringT<T,S>::value_type* s1, const CryStackStringT<T,S>& s2)
{ return s2.compare(s1) >= 0; }
template <class T, size_t S> inline bool operator>=(const CryStackStringT<T,S>& s1, const CryStackStringT<T,S>& s2)
{ return s1.compare(s2) >= 0; }
template <class T, size_t S> inline bool operator>=(const CryStackStringT<T,S>& s1, const typename CryStackStringT<T,S>::value_type* s2)
{ return s1.compare(s2) >= 0; }
template <class T, size_t S> inline bool operator>=(const typename CryStackStringT<T,S>::value_type* s1, const CryStackStringT<T,S>& s2)
{ return s2.compare(s1) <= 0; }

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::operator=( value_type ch )
{
	_Assign( &ch,1 );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S> operator+( const CryStackStringT<T,S>& string1,typename CryStackStringT<T,S>::value_type ch )
{
	CryStackStringT<T,S> s(string1);
	s.append(1,ch);
	return s;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S> operator+( typename CryStackStringT<T,S>::value_type ch, const CryStackStringT<T,S>& str )
{
	CryStackStringT<T,S> s;
	s.reserve(str.size()+1);
	s.append(1,ch);
	s.append(str);
	return s;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S>
inline CryStackStringT<T,S> operator+( const CryStackStringT<T,S>& string1, const CryStackStringT<T,S>& string2 )
{
	CryStackStringT<T,S> s(string1);
	s.append( string2 );
	return s;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S> operator+( const CryStackStringT<T,S>& str1, const typename CryStackStringT<T,S>::value_type* str2 )
{
	CryStackStringT<T,S> s(str1);
	s.append( str2 );
	return s;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S> operator+( const typename CryStackStringT<T,S>::value_type* str1, const CryStackStringT<T,S>& str2 )
{
	assert(str1 == NULL || (CryStackStringT<T,S>::_IsValidString(str1)));
	CryStackStringT<T,S> s;
	s.reserve(  CharTraits<T>::_strlen(str1) + str2.size() );
	s.append(str1);
	s.append(str2);
	return s;
}

template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::operator=(const CryStackStringT<T,S>& str)
{
	_Assign (str.c_str(), str.length() );
	return *this;
}

template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::operator=( const_str str )
{
	assert(str == NULL || _IsValidString(str));
	_Assign( str,this->_strlen(str) ) ;
	return *this;
}

#if defined(PS3) || defined(LINUX) || defined(CAFE)
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::operator=( const CryStringT<T> &str )
{
	_Assign( str.c_str(),str.size() ) ;
	return *this;
}

template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::operator+=( const CryStringT<T> &str )
{
	_ConcatenateInPlace( str.c_str(),str.size() );
	return *this;
}
#endif

template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::operator+=( const_str str )
{
	assert(str == NULL || _IsValidString(str));
	_ConcatenateInPlace( str,this->_strlen(str) );
	return *this;
}

template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::operator+=( value_type ch )
{
	_ConcatenateInPlace( &ch,1 );
	return *this;
}

template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::operator+=( const CryStackStringT<T,S>& str )
{
	_ConcatenateInPlace( str.m_str,str.length() );
	return *this;
}

//! find first single character
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find( value_type ch,size_type pos ) const
{
	if (!( /*pos >= 0 && */pos <= length()) )
		return (typename CryStackStringT<T,S>::size_type)npos;
	const_str str = CharTraits<T>::_strchr( m_str+pos,ch );
	// return npos if not found and index otherwise
	return (str == NULL) ? npos : (size_type)(str - m_str);
}

//! find a sub-string (like strstr)
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find( const_str subs,size_type pos ) const
{
	assert( _IsValidString(subs) );
	if (!( pos >= 0 && pos <= length()) )
		return npos;

	// find first matching substring
	const_str str = CharTraits<T>::_strstr( m_str+pos,subs );

	// return npos for not found, distance from beginning otherwise
	return (str == NULL) ? npos : (size_type)(str - m_str);

}

//! find last single character
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::rfind( value_type ch,size_type pos ) const
{
	const_str str;
	if (pos == npos) {
		// find last single character
		str = strrchr( m_str,ch );
		// return -1 if not found, distance from beginning otherwise
		return (str == NULL) ? (size_type)-1 : (size_type)(str - m_str);
	} else {
		if (pos == npos)
			pos = length();
		if (!( pos >= 0 && pos <= length()) )
			return npos;

		value_type tmp = m_str[pos+1];
		m_str[pos+1] = 0;
		str = strrchr( m_str,ch );
		m_str[pos+1] = tmp;
	}
	// return -1 if not found, distance from beginning otherwise
	return (str == NULL) ? (size_type)-1 : (size_type)(str - m_str);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find_first_of( const CryStackStringT<T,S>& _Str, size_type _Off ) const
{
	return find_first_of( _Str.m_str,_Off );
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find_first_of( value_type _Ch,size_type nOff ) const
{
	if (!( nOff >= 0 && nOff <= length()) )
		return npos;
	value_type charSet[2] = { _Ch,0 };
	const_str str = strpbrk( m_str+nOff,charSet );
	return (str == NULL) ? -1 : (size_type)(str - m_str);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find_first_of( const_str charSet,size_type nOff ) const
{
	assert(_IsValidString(charSet));
	if (!( nOff >= 0 && nOff <= length()) )
		return npos;
	const_str str = strpbrk( m_str+nOff,charSet );
	return (str == NULL) ? (size_type)-1 : (size_type)(str - m_str);
}

//size_type find_first_not_of(const _Self& __s, size_type __pos = 0) const 
//{ return find_first_not_of(__s._M_start, __pos, __s.size()); }

//size_type find_first_not_of(const _CharT* __s, size_type __pos = 0) const 
//{ _STLP_FIX_LITERAL_BUG(__s) return find_first_not_of(__s, __pos, _Traits::length(__s)); }

//size_type find_first_not_of(const _CharT* __s, size_type __pos,	size_type __n) const;

//size_type find_first_not_of(_CharT __c, size_type __pos = 0) const;


//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find_first_not_of( const value_type* _Ptr,size_type _Off ) const
{ return find_first_not_of( _Ptr,_Off,this->_strlen(_Ptr) ); }

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find_first_not_of( const CryStackStringT<T,S>& _Str,size_type _Off ) const
{ return find_first_not_of( _Str.m_str,_Off ); }

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find_first_not_of( value_type _Ch,size_type _Off ) const
{
	if (_Off > length())
		return npos;
	else {
		for (const value_type *str = begin()+_Off; str != end(); ++str)
			if (*str != _Ch)
				return size_type(str - begin()); // Character found!
		return npos;
	}
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline typename CryStackStringT<T,S>::size_type CryStackStringT<T,S>::find_first_not_of( const value_type* _Ptr,size_type _Off,size_type _Count ) const
{
	if (_Off > length())
		return npos;
	else {
		const value_type *charsFirst = _Ptr,*charsLast = _Ptr+_Count;
		for (const value_type *str = begin()+_Off; str != end(); ++str)
		{
			const value_type *c;
			for (c = charsFirst; c != charsLast; ++c)
			{
				if (*c == *str)
					break;
			}
			if (c == charsLast)
				return size_type(str - begin());// Current character not in char set.
		}
		return npos;
	}
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S> CryStackStringT<T,S>::substr( size_type pos, size_type count ) const
{
	if (pos >= length())
		return CryStackStringT<T,S>();
	if (count == npos)
	{
		count = length() - pos;
	}
	if (pos + count > length())
		count = length() - pos;
	return CryStackStringT<T,S>( m_str+pos,count );
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::erase( size_type nIndex,size_type nCount )
{
	if (nIndex < 0)
		nIndex = 0;
	if (nCount < 0 || nCount > length() - nIndex)
		nCount = length() - nIndex;
	if (nCount > 0 && nIndex < length())
	{
		_MakeUnique();
		size_type nNumToCopy = length() - (nIndex + nCount) + 1;
		CharTraits<T>::_move( m_str+nIndex,m_str+nIndex+nCount,nNumToCopy );
		m_nLength = length() - nCount;
	}

	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::insert( size_type nIndex, value_type ch )
{
	return insert(nIndex,1,ch);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::insert( size_type nIndex,size_type nCount,value_type ch )
{
	_MakeUnique();

	if (nIndex < 0)
		nIndex = 0;

	size_type nNewLength = length();
	if (nIndex > nNewLength)
		nIndex = nNewLength;
	nNewLength += nCount;

	if (capacity() < nNewLength)
	{
		value_type* pOldData = m_str;
		size_type nOldLength = m_nLength;
		const_str pstr = m_str;
		_AllocData(nNewLength);
		CharTraits<T>::_copy( m_str,pstr,nOldLength+1 );
		_FreeData(pOldData);
	}

	CharTraits<T>::_move( m_str+nIndex+nCount, m_str+nIndex, (nNewLength-nIndex) );
	CharTraits<T>::_set( m_str+nIndex,ch,nCount );
	m_nLength = nNewLength;
	CRY_STRING_DEBUG(m_str)

		return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::insert( size_type nIndex,const_str pstr,size_type nCount )
{
	if (nIndex < 0)
		nIndex = 0;

	size_type nInsertLength = nCount;
	size_type nNewLength = length();
	if (nInsertLength > 0)
	{
		_MakeUnique();
		if (nIndex > nNewLength)
			nIndex = nNewLength;
		nNewLength += nInsertLength;

		if (capacity() < nNewLength)
		{
			value_type* pOldData = m_str;
			size_type nOldLength = m_nLength;
			const_str pOldStr = m_str;
			_AllocData(nNewLength);
			CharTraits<T>::_copy( m_str, pOldStr,(nOldLength+1) );
			_FreeData(pOldData);
		}

		CharTraits<T>::_move( m_str + nIndex + nInsertLength, m_str + nIndex, (nNewLength-nIndex-nInsertLength+1) );
		CharTraits<T>::_copy( m_str + nIndex, pstr, nInsertLength );
		m_nLength = nNewLength;
		m_str[length()] = 0;
	}
	CRY_STRING_DEBUG(m_str)

		return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::insert( size_type nIndex,const_str pstr )
{
	return insert( nIndex,pstr,this->_strlen(pstr) );
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::replace( size_type pos,size_type count,const_str strNew )
{
	return replace( pos,count,strNew,this->_strlen(strNew) );
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::replace( size_type pos,size_type count,const_str strNew,size_type count2 )
{
	erase( pos,count );
	insert( pos,strNew,count2 );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::replace( size_type pos,size_type count,size_type nNumChars,value_type chNew )
{
	erase( pos,count );
	insert( pos,nNumChars,chNew );
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::replace( value_type chOld,value_type chNew )
{
	if (chOld != chNew)
	{
		_MakeUnique();
		value_type* strend = m_str + length();
		for (value_type* str = m_str; str != strend; ++str)
		{
			if (*str == chOld)
			{
				*str = chNew;
			}
		}
	}
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::replace( const_str strOld,const_str strNew )
{
	size_type nSourceLen = this->_strlen(strOld);
	if (nSourceLen == 0)
		return *this;
	size_type nReplacementLen = this->_strlen(strNew);

	size_type nCount = 0;
	value_type* strStart = m_str;
	value_type* strEnd = m_str + length();
	value_type* strTarget;
	while (strStart < strEnd)
	{
		while ((strTarget = CharTraits<T>::_strstr(strStart, strOld)) != NULL)
		{
			nCount++;
			strStart = strTarget + nSourceLen;
		}
		strStart += this->_strlen(strStart) + 1;
	}

	if (nCount > 0)
	{
		_MakeUnique();

		size_type nOldLength = length();
		size_type nNewLength =  nOldLength + (nReplacementLen-nSourceLen)*nCount;
		if (capacity() < nNewLength)
		{
			value_type* pOldData = m_str;
			size_type nPrevLength = m_nLength;
			const_str pstr = m_str;
			_AllocData(nNewLength);
			CharTraits<T>::_copy( m_str, pstr, nPrevLength );
			_FreeData(pOldData);
		}
		strStart = m_str;
		strEnd = m_str + length();

		while (strStart < strEnd)
		{
			while ( (strTarget = CharTraits<T>::_strstr(strStart, strOld)) != NULL)
			{
				size_type nBalance = nOldLength - ((size_type)( strTarget - m_str) + nSourceLen);
				CharTraits<T>::_move( strTarget + nReplacementLen, strTarget + nSourceLen, nBalance );
				CharTraits<T>::_copy( strTarget, strNew, nReplacementLen );
				strStart = strTarget + nReplacementLen;
				strStart[nBalance] = 0;
				nOldLength += (nReplacementLen - nSourceLen);
			}
			strStart += this->_strlen(strStart) + 1;
		}
		m_nLength = nNewLength;
	}
	CRY_STRING_DEBUG(m_str)

		return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline void CryStackStringT<T,S>::move( CryStackStringT<T,S>& str )
{
	memcpy(this, &str, sizeof(*this));
	if (str.m_str == str.m_strBuf)
		m_str = m_strBuf;
}

template <class T, size_t S> 
inline void CryStackStringT<T,S>::swap( CryStackStringT<T,S>& _Str )
{
	CryStackStringT<T,S> temp;
	temp.move(*this);
	move(_Str);
	_Str.move(temp);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::Format( const_str format,... )
{
	assert(_IsValidString(format));

	value_type temp[4096]; // Limited to 4096 characters!
	va_list argList;
	va_start(argList, format );
	this->_vsnprintf( temp,4095,format,argList ); 
	temp[4095] = '\0';
	va_end(argList);
	*this = temp;
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::FormatFast( const_str format,... )
{
	assert(_IsValidString(format));

	va_list argList;
	va_start(argList, format );
	
	int newLength = this->_vsnprintf( m_str, capacity(), format, argList );
	if (newLength >= 0)
		m_nLength = (size_type)newLength;
	else
	{
		m_nLength = capacity();
		m_str[capacity()] = '\0';
	}

	va_end(argList);

	return *this;
}


//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::MakeLower()
{
	_MakeUnique();
	for (value_type *s = m_str; *s != 0; s++)
	{
		*s = this->_ascii_tolower(*s);
	}
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::MakeLowerLocale()
{
	_MakeUnique();
	for (value_type *s = m_str; *s != 0; s++)
	{
		*s = this->_traits_tolower(*s);
	}
	return *this;
}


//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::MakeUpper()
{
	_MakeUnique();
	for (value_type *s = m_str; *s != 0; s++)
	{
		*s = this->_traits_toupper(*s);
	}
	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::Trim()
{
	return TrimRight().TrimLeft();
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::Trim( value_type ch )
{
	_MakeUnique();
	const value_type chset[2] = { ch,0 };
	return TrimRight(chset).TrimLeft(chset);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::Trim( const value_type *sCharSet )
{
	_MakeUnique();
	return TrimRight(sCharSet).TrimLeft(sCharSet);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::TrimRight( value_type ch )
{
	const value_type chset[2] = { ch,0 };
	return TrimRight(chset);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::TrimRight( const value_type *sCharSet )
{
	if (!sCharSet || !(*sCharSet) || length() < 1)
		return *this;

	const value_type *last = m_str + length()-1;
	const value_type *str = last;
	while( (str != m_str) && (CharTraits<T>::_strchr(sCharSet,*str) != 0))
		str--;

	if (str != last)
	{
		// Just shrink length of the string.
		size_type nNewLength = (size_type)(str - m_str) + 1; // m_str can change in _MakeUnique
		_MakeUnique();
		m_nLength = nNewLength;
		m_str[nNewLength] = 0;
	}

	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::TrimRight()
{
	if (length() < 1)
		return *this;

	const value_type *last = m_str + length() - 1;
	const value_type *str = last;
	while( (str != m_str) && (CharTraits<T>::_isspace(*str) != 0) )
		str--;

	if(str != last)		// something changed?
	{
		// Just shrink length of the string.
		size_type nNewLength = (size_type)(str - m_str) + 1; // m_str can change in _MakeUnique
		_MakeUnique();
		m_nLength = nNewLength;
		m_str[nNewLength] = 0;
	}

	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::TrimLeft( value_type ch )
{
	const value_type chset[2] = { ch,0 };
	return TrimLeft(chset);
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::TrimLeft( const value_type *sCharSet )
{
	if (!sCharSet || !(*sCharSet))
		return *this;

	const value_type *str = m_str;
	while( (*str != 0) && (CharTraits<T>::_strchr(sCharSet,*str) != 0))
		str++;

	if (str != m_str)
	{
		size_type nOff = (size_type)(str - m_str); // m_str can change in _MakeUnique
		_MakeUnique();
		size_type nNewLength = length() - nOff;
		CharTraits<T>::_move( m_str,m_str+nOff,nNewLength+1 );
		m_nLength = nNewLength;
		m_str[nNewLength] = 0;
	}

	return *this;
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S>& CryStackStringT<T,S>::TrimLeft()
{
	const value_type *str = m_str;
	while( (*str != 0) && (CharTraits<T>::_isspace(*str) != 0))
		str++;

	if (str != m_str)
	{
		size_type nOff = (size_type)(str - m_str); // m_str can change in _MakeUnique
		_MakeUnique();
		size_type nNewLength = length() - nOff;
		CharTraits<T>::_move( m_str,m_str+nOff,nNewLength+1 );
		m_nLength = nNewLength;
		m_str[nNewLength] = 0;
	}

	return *this;
}

template <class T, size_t S> 
inline CryStackStringT<T,S> CryStackStringT<T,S>::Right( size_type count ) const
{
	if (count == npos)
		return CryStackStringT<T,S>();
	else if (count > length())
		return *this;

	return CryStackStringT<T,S>( m_str+length()-count,count );
}

template <class T, size_t S> 
inline CryStackStringT<T,S> CryStackStringT<T,S>::Left( size_type count ) const
{
	if (count == npos)
		return CryStackStringT<T,S>();
	else if (count > length())
		count = length();

	return CryStackStringT<T,S>( m_str,count );
}

// strspn equivalent
template <class T, size_t S> 
inline CryStackStringT<T,S> CryStackStringT<T,S>::SpanIncluding( const_str charSet ) const
{
	assert(_IsValidString(charSet));
	return Left( (size_type)this->_strspn(m_str,charSet ) );
}

// strcspn equivalent
template <class T, size_t S> 
inline CryStackStringT<T,S> CryStackStringT<T,S>::SpanExcluding(const_str charSet ) const
{
	assert(_IsValidString(charSet));
	return Left( (size_type)this->_strcspn(m_str,charSet ) );
}

//////////////////////////////////////////////////////////////////////////
template <class T, size_t S> 
inline CryStackStringT<T,S> CryStackStringT<T,S>::Tokenize( const_str charSet, int &nStart ) const
{
	if (nStart < 0)
	{
		return CryStackStringT<T,S>();
	}

	if (!charSet)
		return *this;

	const_str sPlace = m_str + nStart;
	const_str sEnd = m_str + length();
	if (sPlace < sEnd)
	{
		int nIncluding = (int)this->_strspn(sPlace,charSet);

		if ((sPlace+nIncluding) < sEnd)
		{
			sPlace += nIncluding;
			int nExcluding = (int)this->_strcspn(sPlace,charSet);
			int nFrom = nStart+nIncluding;
			nStart = nFrom + nExcluding + 1;

			return substr( nFrom,nExcluding );
		}
	}
	// Return empty string.
	nStart = -1;
	return CryStackStringT<T,S>();
}

//////////////////////////////////////////////////////////////////////////
// Specialization providing efficient move semantics for array classes.
template <class T, size_t S>
bool raw_movable( const CryStackStringT<T,S>& str )
{ 
	return false; 
}

template <class T, size_t S>
void move_init(CryStackStringT<T,S>& dest, CryStackStringT<T,S>& source)
{
	dest.move(source);
}


#if defined(_RELEASE)
#define ASSERT_LEN        (void)(0)


#else
#define ASSERT_LEN        CRY_ASSERT_TRACE(this->length()<=S, ("String '%s' is %u character(s) longer than MAX_SIZE=%u", c_str(), this->length() - S, S))
#endif

// a template specialization for char
template<size_t S> class CryFixedStringT : public CryStackStringT<char, S>
{
public:
	typedef CryStackStringT<char, S> _parentType;
	typedef CryFixedStringT<S> _Self;
	typedef size_t size_type;
	typedef char value_type;
	typedef const value_type* const_str;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef pointer iterator;
	typedef const_pointer const_iterator;
	static const size_type MAX_SIZE = S;
	CryFixedStringT( ) : _parentType() {}
	CryFixedStringT( const _parentType& str ) : _parentType(str) {ASSERT_LEN;}
	CryFixedStringT( const _parentType& str,size_type nOff,size_type nCount ) : _parentType(str, nOff, nCount) {ASSERT_LEN;}
	CryFixedStringT( const _Self& str ) : _parentType(str) {ASSERT_LEN;}
	CryFixedStringT( const _Self& str,size_type nOff,size_type nCount ) : _parentType(str, nOff, nCount) {ASSERT_LEN;}
	explicit CryFixedStringT( value_type ch, size_type nRepeat = 1 ) : _parentType(ch, nRepeat) {ASSERT_LEN;}
	CryFixedStringT( const_str str ) : _parentType (str) {ASSERT_LEN;}
	CryFixedStringT( const_str str, size_type nLength ) : _parentType(str, nLength) {ASSERT_LEN;}
	CryFixedStringT( const_iterator _First,const_iterator _Last ) : _parentType(_First, _Last) {ASSERT_LEN;}

	template<size_t AnySize> _Self& operator=( const CryFixedStringT<AnySize>& str)
	{
		_parentType::operator = (str);
		ASSERT_LEN;
		return *this;
	}
	template<size_t AnySize> _Self& operator=( const CryStackStringT<char, AnySize>& str)
	{
		_parentType::operator = (str);
		ASSERT_LEN;
		return *this;
	}

	void GetMemoryUsage( class ICrySizer *pSizer ) const{}
};

// a template specialization for a fixed list of CryFixedString [Jan M.]
template<size_t maxElements, size_t stringSize>
class CCryFixedStringListT
{
public:
	CCryFixedStringListT()
	{ Clear(); }

	void Clear()
	{
		m_currentAmount = -1;
		for(int a = 0; a < NUM_MAX_ELEMENTS; ++a)
			m_data[a] = "";
	}

	void Add(const char* name)
	{
		m_data[++m_currentAmount] = name;
		if(m_currentAmount == NUM_MAX_ELEMENTS)
			m_currentAmount = -1;
	}

	const char* operator[](int index)
	{
		if(index <= m_currentAmount)
			return m_data[index].c_str();
		return NULL;
	}

	ILINE int Size() { return m_currentAmount+1; }

	CryFixedStringT<32>* GetData(int &amount) 
	{ 
		amount = m_currentAmount+1;
		return m_data; 
	}
private:
	const static int NUM_MAX_ELEMENTS = maxElements;
	CryFixedStringT<stringSize> m_data[NUM_MAX_ELEMENTS];
	int32	m_currentAmount;
};

// a template specialization for wchar_t
template<size_t S> class CryFixedWStringT : public CryStackStringT<wchar_t, S>
{
public:
	typedef CryStackStringT<wchar_t, S> _parentType;
	typedef CryFixedWStringT<S> _Self;
	typedef size_t size_type;
	typedef wchar_t value_type;
	typedef const value_type* const_str;
	typedef value_type* pointer;
	typedef const value_type* const_pointer;
	typedef value_type& reference;
	typedef const value_type& const_reference;
	typedef pointer iterator;
	typedef const_pointer const_iterator;
	static const size_type MAX_SIZE = S;
	CryFixedWStringT( ) : _parentType() {}
	CryFixedWStringT( const _parentType& str ) : _parentType(str) {ASSERT_LEN;}
	CryFixedWStringT( const _parentType& str,size_type nOff,size_type nCount ) : _parentType(str, nOff, nCount) {ASSERT_LEN;}
	CryFixedWStringT( const _Self& str ) : _parentType(str) {ASSERT_LEN;}
	CryFixedWStringT( const _Self& str,size_type nOff,size_type nCount ) : _parentType(str, nOff, nCount) {ASSERT_LEN;}
	explicit CryFixedWStringT( value_type ch, size_type nRepeat = 1 ) : _parentType(ch, nRepeat) {ASSERT_LEN;}
	CryFixedWStringT( const_str str ) : _parentType (str) {ASSERT_LEN;}
	CryFixedWStringT( const_str str, size_type nLength ) : _parentType(str, nLength) {ASSERT_LEN;}
	CryFixedWStringT( const_iterator _First,const_iterator _Last ) : _parentType(_First, _Last) {ASSERT_LEN;}

	template<size_t AnySize> _Self& operator=( const CryFixedWStringT<AnySize>& str)
	{
		_parentType::operator = (str);
		ASSERT_LEN;
		return *this;
	}
	template<size_t AnySize> _Self& operator=( const CryStackStringT<wchar_t, AnySize>& str)
	{
		_parentType::operator = (str);
		ASSERT_LEN;
		return *this;
	}
};
#undef ASSERT_LEN
typedef CryStackStringT<char, 512> stack_string;

// Special string type used for specifying file paths.
typedef CryStackStringT<char, 512> CryPathString;

#if defined(USER_alexl)
struct SUnitTest_FixedString
{
	bool UnitAssert(const char* message, const char* value, const char* refValue)
	{
		int res = strcmp(value, refValue);
		CRY_ASSERT_MESSAGE(res == 0, message);
		return res == 0;
	}

	bool UnitAssert(const char* message, const wchar_t* value, const wchar_t* refValue)
	{
		int res = wcscmp(value, refValue);
		CRY_ASSERT_MESSAGE(res == 0, message);
		return res == 0;
	}

	bool UnitAssert(const char* message, bool cond)
	{
		CRY_ASSERT_MESSAGE(cond, message);
		return cond;
	}

	bool UnitAssert(const char* message, size_t a, size_t b)
	{
		CRY_ASSERT_MESSAGE(a == b, message);
		return a == b;
	}

	int UnitTest()
	{
		CryStackStringT<char, 10> str1;
		CryStackStringT<char, 10> str2;
		CryStackStringT<char, 4> str3;
		CryStackStringT<char, 10> str4;
		CryStackStringT<char, 5+1> str5;
		CryStackStringT<wchar_t, 16> wstr1;
		CryStackStringT<wchar_t, 255> wstr2;
		CryFixedStringT<100> fixedString100;
		CryFixedStringT<200> fixedString200;

		typedef CryStackStringT<char, 10> T;
		T* pStr = new T;
		*pStr = "adads";
		delete pStr;

		str1 = "abcd";
		UnitAssert ("Assignment1-EnoughSpace", str1, "abcd");

		str2 = "efg";
		UnitAssert ("Assignment2-EnoughSpace", str2, "efg");

		str2 = str1;
		UnitAssert ("Assignment3-EnoughSpace", str2, "abcd");

		str3 = str1;
		UnitAssert ("Assignment4-NotEnoughSpace", str3, "abcd");

		str1 += "XY";
		UnitAssert ("Concatenate-EnoughSpace", str1, "abcdXY");

		str2 += "efghijk";
		UnitAssert ("Concatenate-NotEnoughSpace", str2, "abcdefghijk");

		str1.replace("bc", "");
		UnitAssert ("Replace-Shrink-EnoughSpace", str1, "adXY");

		str1.replace("XY", "1234");
		UnitAssert ("Replace-Grow-EnoughSpace", str1, "ad1234");

		str1.replace("1234", "1234567890");
		UnitAssert ("Replace-Grow-NotEnoughSpace", str1, "ad1234567890");

		str1.reserve(200);
		UnitAssert ("Reserve200-SameString", str1, "ad1234567890");
		UnitAssert ("Reserve200-Capacity", str1.capacity() == 200);

		str1.reserve(0);
		UnitAssert ("Reserve0-SameString", str1, "ad1234567890");
		UnitAssert ("Reserve0-Capacity==Length", str1.capacity() == str1.length());

		str1.erase(7); // doesn't change capacity
		UnitAssert ("Erase-SameString", str1, "ad12345");

		str4.assign("abc");
		UnitAssert ("Str4 Assignment", str4, "abc");
		str4.reserve(9);
		UnitAssert ("Str4", str4.capacity() >= 9); // capacity is always >= MAX_SIZE-1
		str4.reserve(0);
		UnitAssert ("Str4-Shrink", str4.capacity() >= 9); // capacity is always >= MAX_SIZE-1

		size_t idx = str1.find("123");
		UnitAssert ("Str1-Find", idx == 2); 

		idx = str1.find("123", 3);
		UnitAssert ("Str1-Find", idx == str1.npos);

		wstr1 = L"abc";
		UnitAssert ("WStr1-Assign", wstr1, L"abc");
		UnitAssert ("WStr1-CompareCaseGT", wstr1.compare(L"aBc") > 0);
		UnitAssert ("WStr1-CompareCaseLT", wstr1.compare(L"babc") < 0);
		UnitAssert ("WStr1-CompareNoCase", wstr1.compareNoCase(L"aBc") == 0);

		str1.Format("This is a %s %S with %d params", "mixed", L"string", 3);
		str2.Format("This is a %S %s with %d params", L"mixed", "string", 3);
		UnitAssert ("Str1-Format1", str1, "This is a mixed string with 3 params");
		UnitAssert ("Str1-Format2", str1, str2);

		wstr1.Format(L"This is a %s %S with %d params", L"mixed", "string", 3);
		wstr2.Format(L"This is a %S %s with %d params", "mixed", L"string", 3);
		UnitAssert ("WStr1-Format1", wstr1, L"This is a mixed string with 3 params");
		UnitAssert ("WStr1-Format2", wstr1, wstr2);

		str5.FormatFast("%s", "12345");
		UnitAssert ("Str5-FormatFast", str5, "12345");

		str5.FormatFast("%s", "012345");
		UnitAssert ("Str5-FormatFast-Truncate", str5, "01234");

		fixedString100 = str5;
		str2 = fixedString200;
		fixedString200 = fixedString100;
		UnitAssert ("FixedString-Test2", fixedString100, "01234");
		UnitAssert ("FixedString-Test1", fixedString100, fixedString200);

		CryStackStringT<char, 10> testStr;
		CryFixedStringT<100> testStr2;
		CryFixedWStringT<100> testWStr1;
		string normalString;
		wstring normalWString;
		normalString = string(testStr);
		normalString = string(testStr2);
		normalString.assign(testStr2.c_str());
		// normalString = testStr;  // <- must NOT compile, as we don't allow it!
		// normalWString = testWStr1;  // <- must NOT compile, as we don't allow it!
		normalWString = wstring(testWStr1);
		return 0;
	}
};
#endif // #if defined(USER_alexl)

#endif // __CRYFIXEDSTRING_H__
